/*
 * @Author: liuzelin
 * @Date: 2024-04-20 12:02:58
 * @LastEditors: liuzelin
 * @LastEditTime: 2024-05-12 21:27:42
 * @Description: file content
 */
#pragma once

#include "panda_socket.hpp"
#include "panda_uv_handler.hpp"
#include "uv.h"

namespace PandaImpl {
class ThreadImpl;
class UVHelper;
class UDPSocketImpl;
class TCPSocketImpl;

struct UDPSendData {
  uv_udp_send_t req;
  char *data = nullptr;
  size_t len = 0;
  UDPSocketImpl *socket = nullptr;
};

struct TCPSendData {
  uv_write_t req;
  char *data = nullptr;
  size_t len = 0;
  TCPSocketImpl *socket = nullptr;
};

class SocketImpl {
  friend class UVHelper;

 protected:
  char *buffer_ = nullptr;
  volatile bool bind_address_ = false;
};
class UDPSocketImpl : public Panda::UDPSocket,
                      public SocketImpl,
                      public UVHandler {
  friend class UVHelper;

 public:
  UDPSocketImpl(ThreadImpl *thread);
  ~UDPSocketImpl();
  bool Bind(const Panda::SocketAddress &ip) override;
  void SendTo(char *data, size_t len, Panda::SocketAddress &to) override;
  void SetSocketListener(Panda::UDPSocketListener *l) override {
    listener_ = l;
  }
  const Panda::SocketAddress &GetLocal() override { return local_; }
  void Close() override;
  void OnClose() {}

 private:
  void UpdateLocalAddress();
  Panda::UDPSocketListener *listener_ = nullptr;
  Panda::SocketAddress local_;
  ThreadImpl *thread_ = nullptr;
  uv_udp_t socket_;
  uv_buf_t sendBuffer_;
};

class TCPSocketImpl : public Panda::TCPSocket,
                      public SocketImpl,
                      public UVHandler {
  friend class UVHelper;

 public:
  TCPSocketImpl(ThreadImpl *thread);
  ~TCPSocketImpl();
  const Panda::SocketAddress &GetLocal() override { return local_; }
  const Panda::SocketAddress &GetRemote() override { return remote_; }
  void SetSocketListener(Panda::TCPSocketListener *l) override {
    this->listener_ = l;
  }
  bool Bind(const Panda::SocketAddress &ip) override;
  void Connect(const Panda::SocketAddress &remote) override;
  int Send(char *data, size_t len) override;
  void Listen() override;
  void Close() override;
  void OnClose() {}

 private:
  void OnConnected();
  Panda::TCPSocketListener *listener_ = nullptr;
  Panda::SocketAddress local_;
  Panda::SocketAddress remote_;
  ThreadImpl *thread_ = nullptr;
  uv_tcp_t socket_;
  uv_connect_t connect_;
  uv_buf_t sendBuffer_;
  char *buffer_ = nullptr;
  bool isConnected = false;
};
}  // namespace PandaImpl